#ifndef TRANS_WORKER_H
#define TRANS_WORKER_H

#include <vector>
#include <string>
#include <map>
#include "Node.h"

enum FreqSwpType {
    SWP_DISCRETE = 0,
    SWP_INTERPOL = 1,
    SWP_FAST = 2
};

const std::string LUMP_PORT = "Lump_Port";
const std::string WAVE_PORT = "Wave_Port";

struct Tetr {
    int node[4];
    int boud[4];
    int iBody;    // geomID
    int iMedi;    // idx
};

struct Tria {
    int node[3];
    int iBoud;
    int iTetr;
};

struct Material {
    std::string sName;
    double dEps{ 1 };
    double dTan{ 0 };
    double dSgm{ 0 };
    double dMiu{ 1 };
    double dTanM{ 0 };
    int iTensor{ 0 };
    double vEpsRe[3][3];
    double vMiuRe[3][3];
    double vEpsIm[3][3];
    double vMiuIm[3][3];
    Material() {
        for (int i = 0; i < 3; ++i) {
            for (int j = 0; j < 3; ++j) {
                vEpsRe[i][j] = 0.0;
                vMiuRe[i][j] = 0.0;
                vEpsIm[i][j] = 0.0;
                vMiuIm[i][j] = 0.0;
            }
        }
    }
};

struct Geometry {
    std::string sName;
    std::string sMedi;
    bool bSolvInside{ false };
    int iObjID{ -1 };
    int iSrcID{ -1 };
    int iMedi{ -1 };    // idx
    std::vector<int> vFaceID;
};

struct Boundary {
    std::string sName;
    std::string sType;
    int id{ -1 };
    int iEdgeDn{ -1 };
    int iEdgeUp{ -1 };
    int iTriaHead;
    int iTriaTail;
    double dZ0{ 50.0 };
    std::vector<int> vVoluID;
    std::vector<int> vFaceID;
};

struct PortInfo {
    std::string sName;
    std::string sType;
    int id{ -1 };
    int iEdgeDn{ -1 };
    int iEdgeUp{ -1 };
    Node rc;
    Node ei;
    Node norm;
    double a{ 0.0 };
    double b{ 0.0 };
    double dZ0{ 50.0 };
    double dMag{ 1.0 };
    double dPha{ 0.0 };
};

struct FEM_Para {
    std::string sFreqUnit{ "GHz" };
    std::string sSwpType{ "Interpolate" };  // type of frequency sweep
    double dFreq0{ 0 };
    double dMinFreq{ 0 };
    double dMaxFreq{ 0 };
    int iNumFreq{ 0 };             // number of frequency
    int iNumFars{ 0 };             // number of far field plane
    int iNumNear{ 0 };             // number of near field plane
    int iCurrent{ 0 };             // set whether calculate surface curren
    int iGauss{ 4 };               // number of Gauss point
    int iOrder{ 2 };               // order of basis function
    int iDrivnEigen{ 0 };          // solution type : 0--Driven, 1--Eigenmode
    int iEigModeNum{ 1 };          // mode number of Eigenmode
    int iSolverType{ 0 };          // solver type : 0--LU, 1--Iteration, 2--DDM
    int iMaxIterNum{ 9 };          // max number of iteration for driven mode
    int iAdapMinNum{ 1 };          // min iteration step for adaptive mode
    int iAdapPassed{ 1 };          // min pass time for adaptive mode
    int iAdapMaxNum{ 0 };          // max iteration step for adaptive mode
    double dEigMinFreq{ 0 };       // min frequency(GHz) for Eigenmode
    double dMaxIterErr{ 0.01 };    // max iteration error if using iterate solver
    double dAdaptRatio{ 0.3 };     // max ratio of mesh to be adaptive (xx%)
    double dAdaptDelta{ 0.1 };     // max delta S-parameter for driven mode
    bool bSolvInside{ false };
};

class TransWorker {
public:
    TransWorker() = default;
    ~TransWorker() = default;

    bool fnParseCmdArgu(int argc, char *argv[], std::string &sAedt, std::string &sMesh);

    bool fnLoadAedtFile(std::string &sName);

    bool fnLoadMeshFile(std::string &sName);

    bool fnGetPortCoord();

    bool fnOutputMsh(std::string &sName);

    bool fnOutputTet(std::string &sName);

    bool fnOutputXml(std::string &sName);

private:
    std::vector<Node> m_vR;
    std::vector<Tetr> m_vTetr;
    std::vector<Tria> m_vTria;
    std::vector<Material> m_vMedi;
    std::vector<Geometry> m_vGeom;
    std::vector<Boundary> m_vBoud;
    std::vector<PortInfo> m_vLump;
    std::vector<PortInfo> m_vPort;
    std::map<int, int> m_mapGeom;
    FEM_Para m_para;

    void fnLoadMaterial(std::string &sTxt);

    void fnLoadGeometry(std::string &sTxt);

    void fnLoadBoundary(std::string &sTxt);

    void fnLoadSolvPara(std::string &sTxt);

    void fnLoadSolution(std::string &sTxt);

    void fnLoadPostPara(std::string &sTxt);

    bool fnLinkGeomMedi();

    void fnSetBoundFace(std::map<int, int>& mapFace);

    void fnGetBoundTria();

    void fnTetrMaterial();

    void fnLinkTriaTetr();

    void fnGetWireFrame(PortInfo &port, std::vector<int> &vWire);
};

#endif

